package com.mad.game.view.models;

import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;

import com.mad.game.backend.GameDemo;
import com.mad.game.system.GameSystem;
import com.mad.game.system.Timer;
import com.mad.game.system.Vector2;

public abstract class GameModel {

	public static final float GRAVITY_CONST = 9.81f ; 
	public static final float GRAVITY_SCALE = 150 ; 
	
	public static final float GRAVITY = 
		((GRAVITY_CONST * GameSystem.TARGET_DELTA_UPDATE_TIME) / GRAVITY_SCALE); 
		
	private Point position ;
	private Dimension size ; 
	private boolean fixed = false ; 
	private boolean gravityInfluenced = true ; 
	private Vector2 currentVelocity ; 
	private Timer timer ;

	public Point getPosition() {
		return position;
	}

	public void setPosition(Point position) {
		this.position = position;
	}
	
	public Dimension getSize() {
		return size;
	}

	public void setSize(Dimension size) {
		this.size = size;
	}

	public boolean isFixed() {
		return fixed;
	}

	public void setFixed(boolean fixed) {
		this.fixed = fixed;
	}

	public boolean isGravityInfluenced() {
		return gravityInfluenced;
	}

	public void setGravityInfluenced(boolean gravityInfluenced) {
		this.gravityInfluenced = gravityInfluenced;
	}

	public Vector2 getCurrentVelocity() {
		return currentVelocity;
	}

	public void setCurrentVelocity(Vector2 currentVelocity) {
		this.currentVelocity = currentVelocity;
	}

	private GameModel() {
		this.setCurrentVelocity(Vector2.NULL_VECTOR); 
		this.timer = new Timer(); 
		timer.getDelta(); 
	}
	
	private GameModel(Point position){
		this(); 
		this.setPosition(position);
	}

	public GameModel(Point position, Dimension size){
		this(position);
		this.setSize(size);
	}

	public void move(Vector2 velocity) {
		int x = (int) (this.getPosition().getX() + velocity.getX());
		int y = (int) (this.getPosition().getY() + velocity.getY());
//		int vx = this.currentVelocity.getX(); 
//		int vy = this.currentVelocity.getY();
//		this.setCurrentVelocity(new Vector2(velocity.getX()+vx, velocity.getY()+vy));
//		if(!GameDemo.getGameInstance().doesModelCollide(this))
			this.setPosition(new Point(x, y));
//		this.setCurrentVelocity(new Vector2(vx, vy)); 
	}
	
	public void update(){
		if(!this.isFixed()){
			if(!GameDemo.getGameInstance().doesModelCollide_inMovement(this)){
				int vx = this.getCurrentVelocity().getX(); 
				int gravity = (int) (this.isGravityInfluenced() ? GRAVITY : 0) ; 
				int vy = (int) (this.getCurrentVelocity().getY() - gravity);
				this.setCurrentVelocity(new Vector2(vx, vy)); 
				this.move(this.currentVelocity);
			}
			else{
//				while(!GameDemo.getGameInstance().doesModelCollide(this))
//					this.move(this.currentVelocity.transformToUnitVector());
				int vx = this.getCurrentVelocity().getX(); 
				int vy = this.getCurrentVelocity().getY();
				Vector2 vel = Vector2.NULL_VECTOR ; 
				if(vx != 0)	vel = new Vector2(0, vy); 
				this.setCurrentVelocity(vel);
			}	
		}
	}
	
	public static Rectangle calculateBoundingRectangle(GameModel model){
		return new Rectangle((int)model.position.getX(), (int)model.position.getY(),
							(int)model.size.getWidth(), (int)model.size.getHeight()); 
	}

	public static Rectangle calculateVelocityRectangle(GameModel model){
		int vx = model.getCurrentVelocity().getX(); 
		int vy = model.getCurrentVelocity().getY(); 
		int vxAbs = Math.abs(vx); 
		int vyAbs = Math.abs(vy);
		int x = (int) model.getPosition().getX(),
			y = (int) model.getPosition().getY(),
			w = (int) model.getSize().getWidth(),
			h = (int) model.getSize().getHeight() ; 
		w += vxAbs ; 
		h += vyAbs ; 
		if(vx < 0) x -= vxAbs ; 
		if(vy < 0) y -= vyAbs ; 
		return  new Rectangle(x,y,w,h) ;
	}
		
	public static boolean doModelsCollide_inMovement(GameModel model1, GameModel model2){
		Rectangle r1 = calculateVelocityRectangle(model1); 
		Rectangle r2 = calculateVelocityRectangle(model2);
		return r2.intersects(r1); 
//		return (Math.abs(model1.position.getX() - model2.position.getX()) * 2 < 
//						(model1.size.getWidth() + model2.size.getWidth()) && 
//				Math.abs(model1.position.getY() - model2.position.getY()) * 2 < 
//						(model1.size.getHeight() + model2.size.getHeight())); 
//		return !(
//				r2.getMinX() > r1.getMaxX()
//				|| r2.getMaxX() < r1.getMinX()
//				|| r2.getMaxY() > r1.getMinY()
//				|| r2.getMinY() < r1.getMaxY()
//			);
	}
	

	public static boolean doModelsCollide(GameModel model1, GameModel model2){
		Rectangle r1 = calculateBoundingRectangle(model1);
		Rectangle r2 = calculateBoundingRectangle(model2);
		return r2.intersects(r1);
	}
	
}
